/******************************************************************************************
文件名：loice_slave_parser.c
作者：狼狼    版本：Loice    创建日期：2021.8.27
文件描述：
    Loice Slave侧解析器（会话）示例。
历史修改记录：
1. 2021-8-27:Loice 狼狼
创建。
2. 2022-5-11:Loice 狼狼
代码公开。
******************************************************************************************/
//+------------------------------------------------------------------------------------------+
//|                                            前言
//+------------------------------------------------------------------------------------------+
//|      在OSI七层模型中，UDP、TCP为传输层协议，其上有会话层、表示层和应用层，当基于传输层协议
//|  设计应用层通信协议时，协议中必须有涉及会话、表示和应用层数据荷载的字段。
//|      在本例使用的Loice通信协议版本一中，对于不同的TCP连接，使用会话ID号实现会话的区分，使
//|  用指令/数据ID和指令/数据Value实现不同信息的表示，最后使用变长荷载描述为不同的数据提供统
//|  一的传输方式。
//|      对于该协议，解析器要完成的功能为：区分不同的会话，为不同的会话提供指令/数据等不同应用
//|  层数据类型的解析，将协议承载的应用层数据重新打包为内部指令并发往如指令管理或执行核心等模
//|  块。
//+------------------------------------------------------------------------------------------+
//|                                          文件说明
//+------------------------------------------------------------------------------------------+
//|      本文件中定义了用于描述一个解析器本身的结构和用于描述解析器管理所的会话的结构，会话附
//|  着于解析器，解析器从不同的会话获取数据并将其转译为内部指令，同时提供向不同会话发送数据的
//|  接口。
//|      [特别说明]在Loice通信模型中，通信双方角色不对等，Loice从设备接收来自Loice主设备的指
//|  令消息并将必要的数据回应发送给主设备。但Loice从设备不能向Loice主设备发送指令。当Loice从
//|  设备想要向Loice主设备上报信息时，可以使用REPORT消息类型（当前受限于开发时间暂未实现），如
//|  果Loice主设备实现（并使能）了对该类型数据的接收，则可对上报的数据进行处理。详见《Loice（
//|  恒音）通信协议规定》。
//|      [注意]当前文件实现Loice Slave侧解析器，支持的解析内容包含如指令类，支持的发送内容为数
//|  据和指令回应类。
//|      [注意]当前实现中，未对各TCP连接使用多路复用机制，因为Loice从设备虽然从机制上可以同时
//|  对接多个主设备，但使用中一般仅对接一个，因此本工程在设计时对每个会话创建了独立的收发和解
//|  析线程。
//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/#include <stdio.h>
/*|*/#include <string.h>
/*|*/#include <stdlib.h>
/*|*/#include <stdint.h>
/*|*/#include <stdbool.h>
/*|*/#include <unistd.h>
//|
/*|*/#include "loice_slave_parser.h"
/*|*/#include "cmd_verify.h"
/*|*/#include "cmd_reg_table.h"
/*|*/#include "project_debug.h"
//+------------------------------------------------------------------------------------------+
//|                                          全局变量
//+------------------------------------------------------------------------------------------+
/*|*/static const uint8_t device_id_zero[28] = {0}; // 用于设备匹配部分
/*|*/extern int internal_cmd_pipe[2]; // 用于内部指令转发的管道描述符
//+------------------------------------------------------------------------------------------+
//|  函数名称：internal_cmd_match
//|  功能描述：内部指令匹配，查找目标指令是否被注册
//|  参数说明：ENUM_CMD_ID枚举，指令值
//|  返回值说明：指令记录表中存在该指令则返回位置，否则返回-1
//|  备注：该函数同时被用于执行过程中的指令回调匹配，因此需要extern属性。
//+------------------------------------------------------------------------------------------+
int internal_cmd_match(ENUM_CMD_ID cmd_id, uint16_t cmd_value)
{
    int i = 0;
    do
    {
        if(cmd_reg_table[i].cmd_id == cmd_id && cmd_reg_table[i].cmd_value == cmd_value)
        {
            return i;
        }
        i++;
    }while(cmd_reg_table[i].cmd_id != CMD_RESERVED);
    
    return -1;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：array_compare
//|  功能描述：数组比较
//|  参数说明：指向两个数组的指针，比较长度
//|  返回值说明：两数组完全一致返回0，否则返回-1
//|  备注：
//+------------------------------------------------------------------------------------------+
static int array_compare(const uint8_t array1[], const uint8_t array2[], uint32_t compare_len)
{
    for(int i = 0; i < compare_len; i++)
    {
        if(array1[i] != array2[i])return -1;
    }
    
    return 0;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_get_data_to_buf
//|  功能描述：Loice协议版本1指令获取指定长度的数据信息，存储到指定位置
//|  参数说明：指向解析器会话实例的指针，指向目标存储区的指针，待接收的数据长度
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回-1
//|  备注：若解析器会话中的接收缓冲区没有足够的数据，将阻塞等待直到缓冲区状态改变。
//+------------------------------------------------------------------------------------------+
static int loice_proto_version1_get_data_to_buf(ST_PARSER_SESSION *pparser_session_obj, 
                                                      uint8_t *pbuf, uint32_t remain_len)
{
    int ret = 0;
    uint8_t *pdata = NULL;
    int cpy_pos = 0;
    while(remain_len != 0)
    {
        uint32_t data_len = 0;
        ret = pparser_session_obj->ptcpcomm_obj->wait_for_data(pparser_session_obj->ptcpcomm_obj);
        if(ret < 0)
        {
            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:wait_for_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
            pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
            return -1;
        }
        ret = pparser_session_obj->ptcpcomm_obj->get_data_len(pparser_session_obj->ptcpcomm_obj, &data_len);
        if(ret < 0)
        {
            OUTPUT("[PARSER-ERROR]Parser process[Session ID:%d]:get_data_len failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
            pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
            return -1;
        }
        pdata = NULL;
        ret = pparser_session_obj->ptcpcomm_obj->get_data_point(pparser_session_obj->ptcpcomm_obj, &pdata);
        if(ret < 0)
        {
            OUTPUT("[PARSER-ERROR]Parser process[Session ID:%d]:get_data_point failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
            pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
            return -1;
        }
        if(data_len >= remain_len)
        {
            memcpy(pbuf + cpy_pos, pdata, remain_len);
            ret = pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, remain_len);
            if(ret < 0)
            {
                OUTPUT("[PARSER-ERROR]Parser process[Session ID:%d]:update_data_point failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
                return -1;
            }
            cpy_pos = 0;/* 无用 */
            remain_len -= remain_len;
        }
        else
        {
            memcpy(pbuf + cpy_pos, pdata, data_len);
            ret = pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, data_len);
            if(ret < 0)
            {
                OUTPUT("[PARSER-ERROR]Parser process[Session ID:%d]:update_data_point failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
                return -1;
            }
            remain_len -= data_len;
            cpy_pos += data_len;
        }
    }
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_data_body_checksum_calcu
//|  功能描述：Loice协议版本1数据体校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_BODY_MSG结构体的指针，pdata成员数据长度
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标校验和成员
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_data_body_checksum_calcu(const ST_LOICE_PROTO_VER_1_BODY_MSG *pdata_body, uint32_t data_len)
{
    uint16_t checksum_calcu = 0;
    
    checksum_calcu += pdata_body->data_type;
    checksum_calcu += (uint8_t)((pdata_body->data_type_value & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pdata_body->data_type_value & 0xFF);
    checksum_calcu += (uint8_t)((pdata_body->data_seq & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pdata_body->data_seq & 0xFF);
    if(pdata_body->pdata != NULL && data_len != 0)
    {
        for(uint32_t i = 0; i < data_len; i++)
        {
            checksum_calcu += *(pdata_body->pdata + i);
        }
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_cmd_body_checksum_calcu
//|  功能描述：Loice协议版本1指令体校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_BODY_CMD结构体的指针,pdata成员数据长度
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标校验和成员
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_cmd_body_checksum_calcu(const ST_LOICE_PROTO_VER_1_BODY_CMD *pcmd_body, uint32_t data_len)
{
    uint16_t checksum_calcu = 0;
    
    checksum_calcu += pcmd_body->cmd_id;
    checksum_calcu += pcmd_body->reserved1;
    checksum_calcu += (uint8_t)((pcmd_body->cmd_value & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pcmd_body->cmd_value & 0xFF);
    checksum_calcu += (uint8_t)((pcmd_body->reserved2 & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pcmd_body->reserved2 & 0xFF);
    
    if(pcmd_body->pdata != NULL && data_len != 0)
    {
        for(uint32_t i = 0; i < data_len; i++)
        {
            checksum_calcu += *(pcmd_body->pdata + i);
        }
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_head_checksum_calcu
//|  功能描述：Loice协议版本1指令首部校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_HEAD结构体的指针
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标首部的校验和字段
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_head_checksum_calcu(const ST_LOICE_PROTO_VER_1_HEAD *pmsg_head)
{
    uint16_t checksum_calcu = 0;
    uint8_t *pu8msg_head = (uint8_t *)pmsg_head;
    
    for(int i = 0; i < sizeof(ST_LOICE_PROTO_VER_1_HEAD) - 2; i++)
    {
        checksum_calcu += (uint16_t)(*pu8msg_head);
        pu8msg_head++;
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_msg_head_build
//|  功能描述：Loice协议版本1消息首部构建工具
//|  参数说明：指向解析器会话实例的指针，输出指令帧首部结构指针，回应信息中“消息类型”字段设置值
//|  返回值说明：无
//|  备注：使用该函数构建的目的ID号字段为0
//+------------------------------------------------------------------------------------------+
static void loice_proto_version1_msg_head_build(const ST_PARSER_SESSION *pparser_session_obj, 
                                                      ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_output, 
                                                      ST_INTERNAL_DATA *pinternal_data,
                                                      ENUM_MESSAGE_TYPE enum_msg_type)
{
    memset(pmsg_head_output, 0, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
    pmsg_head_output->head[0] = 0x14;
    pmsg_head_output->head[1] = 0xCF;
    pmsg_head_output->head[2] = 0x92;
    pmsg_head_output->head[3] = 0x5A;
    pmsg_head_output->head[4] = 0xA0;
    pmsg_head_output->head[5] = 0xC0;
    pmsg_head_output->head[6] = 0x00;
    pmsg_head_output->head[7] = 0xFF;
    memcpy(pmsg_head_output->source_device_id, pparser_session_obj->local_device_id, 24);
    pmsg_head_output->protocol_version = PARSER_PROTOCOL_1;
    pmsg_head_output->msg_seq          = pinternal_data->msg_seq; /* 对应指令的序列号，用于区分对哪条指令的响应 */
    pmsg_head_output->msg_timestamp    = 0; /* 时间戳当前未实现 */
    pmsg_head_output->payload_length   = pinternal_data->data_length + MIN_PAYLOAD_DATA_LENGTH;
    pmsg_head_output->msg_type         = enum_msg_type;
    pmsg_head_output->msg_head_check   = loice_proto_version1_head_checksum_calcu(pmsg_head_output);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_cmd_reply_build
//|  功能描述：Loice协议版本1指令回应报文构建工具
//|  参数说明：指向解析器会话实例的指针，待回应的原指令帧首部结构，回复指令帧首部结构，回应信息中“消息类型”字段设置值
//|  返回值说明：无
//|  备注：回应报文不包含任何长度的荷载部分，仅具有首部字段。
//+------------------------------------------------------------------------------------------+
static void loice_proto_version1_cmd_reply_build(const ST_PARSER_SESSION *pparser_session_obj, 
                                                 const ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_source, 
                                                       ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_reply, 
                                                       ENUM_MESSAGE_TYPE enum_msg_type)
{
    memset(pmsg_head_reply, 0, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
    memcpy(pmsg_head_reply->head, pmsg_head_source->head, 8);
    memcpy(pmsg_head_reply->source_device_id, pparser_session_obj->local_device_id, 24);
    memcpy(pmsg_head_reply->destination_device_id, pmsg_head_source->source_device_id, 24);
    pmsg_head_reply->protocol_version = PARSER_PROTOCOL_1;
    pmsg_head_reply->msg_seq          = pmsg_head_source->msg_seq;
    pmsg_head_reply->msg_timestamp    = 0; /* 时间戳当前未实现 */
    pmsg_head_reply->payload_length   = 0; /* Fixed */
    pmsg_head_reply->msg_type         = enum_msg_type;
    pmsg_head_reply->msg_head_check   = loice_proto_version1_head_checksum_calcu(pmsg_head_reply);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_version1_process
//|  功能描述：协议版本1指令解析处理线程入口函数
//|  参数说明：指向解析器会话实例的指针
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
static void *parser_version1_process(void *p)
{
    int ret;
    bool flag_current_reply = true;
#ifdef ENABLE_KAP
    bool flag_kap_reply = true;
#endif
    uint8_t *pdata = NULL;
    ST_LOICE_PROTO_VER_1_HEAD msg_head = 
    {
        {0x14, 0xCF, 0x92, 0x5A, 0xA0, 0xC0, 0x00, 0xFF},
        /* 剩余成员填充为0 */
    };
    ST_PARSER_SESSION *pparser_session_obj = (ST_PARSER_SESSION *)p;
    
    while(pparser_session_obj->flag_run)
    {
PARSER_VER1_PROCESS_START:
        flag_current_reply = true;
#ifdef ENABLE_KAP
        flag_kap_reply     = true; // 每轮指令判断都重新置位
#endif
        /* 判断帧头 */
        ret = pparser_session_obj->ptcpcomm_obj->wait_for_data(pparser_session_obj->ptcpcomm_obj);
        if(ret < 0)
        {
            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:wait_for_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
            pparser_session_obj->exit_state = PARSER_EXIT_STAT_RX_ERROR;
            goto PARSER_VER1_PROCESS_END;
        }
        pdata = NULL;
        ret = pparser_session_obj->ptcpcomm_obj->get_data_point(pparser_session_obj->ptcpcomm_obj, &pdata);
        switch(*pdata)
        {
            case 0x14:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD1;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0xCF:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD2;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0x92:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD3;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0x5A:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD4;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0xA0:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD5;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0xC0:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD6;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0x00:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD7;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
            case 0xFF:  pparser_session_obj->state = PARSER_SESSION_STAT_GOTHEAD8;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        break;// 使用break跳出帧头查找
            default:    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        pparser_session_obj->ptcpcomm_obj->update_data_point(pparser_session_obj->ptcpcomm_obj, 1);
                        goto PARSER_VER1_PROCESS_START;
        }
        
        /* 接收固定首部的后续部分 */
        ret = loice_proto_version1_get_data_to_buf(pparser_session_obj, (uint8_t *)&msg_head + 8, 
                                                                        sizeof(ST_LOICE_PROTO_VER_1_HEAD) - 8);
        if(ret < 0)goto PARSER_VER1_PROCESS_END;
        
        /* 校验首部信息 */
        uint16_t checksum_calcu = loice_proto_version1_head_checksum_calcu(&msg_head);
        if(checksum_calcu != msg_head.msg_head_check)
        {
            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Wrong head checksum:0x%.4x Calculated checksum:0x%.4x\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.msg_head_check, checksum_calcu);
            pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
            goto PARSER_VER1_PROCESS_START;
        }
        pparser_session_obj->state = PARSER_SESSION_STAT_HEAD_CHECK_PASS;
        
        /* 根据首部“消息类型”字段处理后续动作 */
        switch((ENUM_MESSAGE_TYPE)msg_head.msg_type)
        {
            case CMD_TYPE_NOREPLY:
                flag_current_reply = false; // 置本轮无回应标志
            case CMD_TYPE_NORMAL:
            {
                ST_LOICE_PROTO_VER_1_BODY_CMD cmd_body = {0};
                if(msg_head.payload_length != 0)
                {
                    if(msg_head.payload_length > MAX_PAYLOAD_LENGTH)
                    {
                        /* 荷载数据长度超出限制 */
                        if(flag_current_reply)
                        {
                            ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                            loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_TOO_LONG);
                            ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                                pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                                goto PARSER_VER1_PROCESS_END;
                            }
                        }
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Message is too long[%d]!\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.payload_length);
                        pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        goto PARSER_VER1_PROCESS_START;
                    }
                    if(msg_head.payload_length < MIN_PAYLOAD_LENGTH)
                    {
                        /* 荷载数据长度过少 */
                        if(flag_current_reply)
                        {
                            ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                            loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_TOO_SHORT);
                            ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                                pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                                goto PARSER_VER1_PROCESS_END;
                            }
                        }
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Message is too short[%d]!\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.payload_length);
                        pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        goto PARSER_VER1_PROCESS_START;
                    }
                    
                    /* 接收可变长指令首部 */
                    ret = loice_proto_version1_get_data_to_buf(pparser_session_obj, (uint8_t *)&cmd_body, sizeof(ST_LOICE_PROTO_VER_1_BODY_CMD) - sizeof(uint8_t *));
                    if(ret < 0)goto PARSER_VER1_PROCESS_END;
                    
                    /* 申请地址空间以存储变长部分 */
                    if(msg_head.payload_length - MIN_PAYLOAD_LENGTH == 0)
                    {
                        cmd_body.pdata = NULL;
                    }
                    else
                    {
                        uint8_t *ptmp = (uint8_t *)malloc(msg_head.payload_length - MIN_PAYLOAD_LENGTH);
                        if(ptmp == NULL)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Malloc failed!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_MALLOC_ERROR;
                            goto PARSER_VER1_PROCESS_END;
                        }
                        
                        ret = loice_proto_version1_get_data_to_buf(pparser_session_obj, ptmp, msg_head.payload_length - MIN_PAYLOAD_LENGTH);
                        if(ret < 0)goto PARSER_VER1_PROCESS_END;
                        
                        cmd_body.pdata = ptmp;
                    }
                    
                    /* 校验消息体 */
                    uint16_t checksum_calcu = loice_proto_version1_cmd_body_checksum_calcu(&cmd_body, msg_head.payload_length - MIN_PAYLOAD_LENGTH);
                    if(checksum_calcu != cmd_body.cmd_body_check)
                    {
                        if(flag_current_reply)
                        {
                            ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                            loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_WRONG_CHECK);
                            ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                                pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                                if(cmd_body.pdata)free(cmd_body.pdata);
                                goto PARSER_VER1_PROCESS_END;
                            }
                        }
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Wrong cmd body checksum:0x%.4x Calculated checksum:0x%.4x\n", pparser_session_obj->ptcpcomm_obj->session_id, cmd_body.cmd_body_check, checksum_calcu);
                        pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        if(cmd_body.pdata)free(cmd_body.pdata);
                        goto PARSER_VER1_PROCESS_START;
                    }
                    pparser_session_obj->state = PARSER_SESSION_STAT_CMD_BODY_CHECK_PASS;
                }
                else
                {
                    if(flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_CMD_EMPTY);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Payload is 0!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    goto PARSER_VER1_PROCESS_START;
                }
                
                /* 设备ID匹配判断 */
                if(array_compare(msg_head.destination_device_id, device_id_zero, 24) != 0)
                {
                    if(array_compare(msg_head.destination_device_id, pparser_session_obj->local_device_id, 24) != 0)
                    {
                        if(flag_current_reply)
                        {
                            ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                            loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_WRONG_ID);
                            ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                                pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                                if(cmd_body.pdata)free(cmd_body.pdata);
                                goto PARSER_VER1_PROCESS_END;
                            }
                        }
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Unmatch device ID!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                        pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        if(cmd_body.pdata)free(cmd_body.pdata);
                        goto PARSER_VER1_PROCESS_START;
                    }
                }
                pparser_session_obj->state = PARSER_SESSION_STAT_MSG_ID_CHECK_PASS;
                
#ifdef ENABLE_SEQ_CHECK
                /* 指令时效判断 */
                if(msg_head.msg_seq <= pparser_session_obj->max_msg_seq && msg_head.msg_seq != 0)
                {
                    if(flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_OLD_CMD);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            if(cmd_body.pdata)free(cmd_body.pdata);
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Expired command[%d <= %d]!\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.msg_seq, pparser_session_obj->max_msg_seq);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    if(cmd_body.pdata)free(cmd_body.pdata);
                    goto PARSER_VER1_PROCESS_START;
                }
                pparser_session_obj->state = PARSER_SESSION_STAT_MSG_SEQ_CHECK_PASS;
                pparser_session_obj->max_msg_seq = msg_head.msg_seq;//记录当前有效指令头的序列号
                if(msg_head.msg_seq == 0)//溢出重置
                {
                    pparser_session_obj->max_msg_seq = 0;
                }
#endif
                
                /* 指令注册判断 */
                if(internal_cmd_match(cmd_body.cmd_id, cmd_body.cmd_value) < 0)
                {
                    if(flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_NOT_FOUND);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            if(cmd_body.pdata)free(cmd_body.pdata);
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Command not found!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    if(cmd_body.pdata)free(cmd_body.pdata);
                    goto PARSER_VER1_PROCESS_START;
                }
                pparser_session_obj->state = PARSER_SESSION_STAT_CMD_REG_CHECK_PASS;
                
                /* 内部指令构建 */
                ST_INTERNAL_CMD internal_cmd = {0};
                internal_cmd.session_id = pparser_session_obj->ptcpcomm_obj->session_id;
                internal_cmd.cmd_id     = (ENUM_CMD_ID)(cmd_body.cmd_id);
                internal_cmd.cmd_value  = cmd_body.cmd_value;
                internal_cmd.msg_seq    = msg_head.msg_seq;
                internal_cmd.pargs      = cmd_body.pdata;
                
                /* 指令参数判断 */
                if(internal_cmd_args_verify(&internal_cmd) != 0)
                {
                    if(flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_WRONG_ARGS);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            if(internal_cmd.pargs)free(internal_cmd.pargs);
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Illegal arguments!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    if(internal_cmd.pargs)free(internal_cmd.pargs);
                    goto PARSER_VER1_PROCESS_START;
                }
                pparser_session_obj->state = PARSER_SESSION_STAT_CMD_VERIFY_PASS;
                
                /* 系统忙状态判断 */
                if(internal_cmd.cmd_id == CMD_ACTION && pparser_session_obj->flag_is_CMD_ACTION_run)
                {
                    if(flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_BUSY);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            if(internal_cmd.pargs)free(internal_cmd.pargs);
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:System is busy now!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    if(internal_cmd.pargs)free(internal_cmd.pargs);
                    goto PARSER_VER1_PROCESS_START;
                }
                pparser_session_obj->state = PARSER_SESSION_STAT_CMD_ACTION_CHECK_PASS;
                
                /* 正常回应报文构建 */
                if(flag_current_reply)
                {
                    ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                    loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, CMD_REPLY_OK);
                    ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                    if(ret < 0)
                    {
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                        pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                        if(internal_cmd.pargs)free(internal_cmd.pargs);
                        goto PARSER_VER1_PROCESS_END;
                    }
                }
                
                /* 打印指令/数据详情 & 内部转发 */
                // printf("[PARSER-TEST][Session ID:%d][Seq:%d]Recv command[ID:%d - Value:%d]\n", pparser_session_obj->ptcpcomm_obj->session_id, internal_cmd.msg_seq, internal_cmd.cmd_id, internal_cmd.cmd_value);
                // if(internal_cmd.pargs)free(internal_cmd.pargs);//Only for test，用于防止内存泄漏
                
                write(internal_cmd_pipe[1], (uint8_t *)&internal_cmd, sizeof(ST_INTERNAL_CMD));
                
                /* 若转发阻塞Action指令，则需置位标志位，执行完成后在后级应用中调用清除标志位的方法 */
                if(internal_cmd.cmd_id == CMD_ACTION)
                {
                    pparser_session_obj->flag_is_CMD_ACTION_run = true;
                }
                
#ifdef ENABLE_KAP
                /* 更新KAP时间记录 */
                gettimeofday(&pparser_session_obj->last_kap_time, NULL);
#endif
            }
            break;
#ifdef ENABLE_KAP
            case KAP_TYPE_NOREPLY:
                flag_kap_reply = false; // 置本轮无回应标志
            case KAP_TYPE_NORMAL:
            {
                /* KAP消息无附加信息，因此荷载长度应为0 */
                if(msg_head.payload_length != 0)
                {
                    if(flag_kap_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, KAP_REPLY_TOO_LONG);
                        ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                            pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                            goto PARSER_VER1_PROCESS_END;
                        }
                    }
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:KAP payload is too long[%d != 0]!\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.payload_length);
                    pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                    goto PARSER_VER1_PROCESS_START;
                }
                
                /* 设备ID匹配判断 */
                if(array_compare(msg_head.destination_device_id, device_id_zero, 24) != 0)
                {
                    if(array_compare(msg_head.destination_device_id, pparser_session_obj->local_device_id, 24) != 0)
                    {
                        if(flag_kap_reply)
                        {
                            ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                            loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, KAP_REPLY_WRONG_ID);
                            ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                                pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                                goto PARSER_VER1_PROCESS_END;
                            }
                        }
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:KAP:Unmatch device ID!\n", pparser_session_obj->ptcpcomm_obj->session_id);
                        pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
                        goto PARSER_VER1_PROCESS_START;
                    }
                }
                
                /* 更新KAP时间记录 */
                gettimeofday(&pparser_session_obj->last_kap_time, NULL);
                
                OUTPUT("[PARSER-DEBUG][Session ID:%d]Recv KAP.\n", pparser_session_obj->ptcpcomm_obj->session_id);
                
                /* 正常KAP回应报文构建 */
                if(flag_kap_reply)
                {
                    ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                    loice_proto_version1_cmd_reply_build(pparser_session_obj, &msg_head, &msg_head_reply, KAP_REPLY_OK);
                    ret = pparser_session_obj->ptcpcomm_obj->send_data(pparser_session_obj->ptcpcomm_obj, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                    if(ret < 0)
                    {
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:send_data failed with %#x!\n", pparser_session_obj->ptcpcomm_obj->session_id, ret);
                        pparser_session_obj->exit_state = PARSER_EXIT_STAT_TX_ERROR;
                        goto PARSER_VER1_PROCESS_END;
                    }
                    OUTPUT("[PARSER-DEBUG][Session ID:%d]Send KAP Reply.\n", pparser_session_obj->ptcpcomm_obj->session_id);
                }
            }
            break;
#endif
            case DATA_REPLY_OK:
            case DATA_REPLY_WRONG_CHECK:
                /* 当前实现中未对数据消息回应做处理，因此数据打包方法也同时使用无回应消息类型 */
                /* [说明]数据回应设计初衷为提供应用层数据对端接收成功的通知或应用层重传机制，暂未考虑实现 */
            break;
            default:
                OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Loice slave device does not support message type[%d]!\n", pparser_session_obj->ptcpcomm_obj->session_id, msg_head.msg_type);
                pparser_session_obj->state = PARSER_SESSION_STAT_STANDBY;
            break;// aka. goto PARSER_VER1_PROCESS_START;
        }
    }
    
PARSER_VER1_PROCESS_END:
    pparser_session_obj->state = PARSER_SESSION_STAT_EXIT;
    OUTPUT("[PARSER-DEBUG]Session[%d] process thread exit!\n", pparser_session_obj->ptcpcomm_obj->session_id);
    
    pthread_exit(NULL);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_manager_process
//|  功能描述：会话状态管理线程
//|  参数说明：指向解析器实例的指针
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
static void *parser_manager_process(void *p)
{
#ifdef ENABLE_KAP
    struct timeval time_now;
#endif
    ST_PARSER *pparser_obj = (ST_PARSER *)p;
    
    while(pparser_obj->flag_manager_run)
    {
#ifdef ENABLE_KAP
        gettimeofday(&time_now, NULL);
#endif
        
        for(int i = 0; i < MAX_SESSION_NUM; i++)
        {
            if(pparser_obj->session_list[i] != NULL)
            {
                if(pparser_obj->session_list[i]->ptcpcomm_obj->exit_state != TCPCOMM_SUCCESS)
                {
                    OUTPUT("[PARSER-INFO]TCP-Comm exited with state %#x!\n", pparser_obj->session_list[i]->ptcpcomm_obj->exit_state);
                    pparser_obj->delete_session(pparser_obj, &pparser_obj->session_list[i]->ptcpcomm_obj);
                }
                else if(pparser_obj->session_list[i]->exit_state == PARSER_SESSION_STAT_EXIT)
                {
                    OUTPUT("[PARSER-DEBUG]Parser process exited with state %#x!\n", pparser_obj->session_list[i]->ptcpcomm_obj->exit_state);
                    pparser_obj->delete_session(pparser_obj, &pparser_obj->session_list[i]->ptcpcomm_obj);
                }
                
#ifdef ENABLE_KAP
                /* KAP超时判断 */
                else if(time_now.tv_sec - pparser_obj->session_list[i]->last_kap_time.tv_sec > KAP_TIMEOUT)
                {
                    OUTPUT("[PARSER-DEBUG]Parser session[%d] KAP timeout!\n", pparser_obj->session_list[i]->ptcpcomm_obj->session_id);
                    pparser_obj->delete_session(pparser_obj, &pparser_obj->session_list[i]->ptcpcomm_obj);
                }
#endif
            }
        }
        
        sleep(1);
    }
    
    pthread_exit(NULL);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：add_session
//|  功能描述：向解析器增加一个待处理会话
//|  参数说明：指向解析器对象结构的指针，指向TCP_COMM通信对象的指针
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：对会话的标识通过会话ID完成
//+------------------------------------------------------------------------------------------+
static int add_session(struct parser * const parser_obj, ST_TCP_COMM * const ptcpcomm_obj)
{
    /* 对象结构指针状态检查 */
    if(parser_obj == NULL || ptcpcomm_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[add_session]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查当前解析器实例是否以达到最大会话持有数量 */
    if(parser_obj->session_num >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Session list is full!\n");
        return PARSER_ERROR_SESSION_LIST_FULL;
    }
    
    /* 检查解析器会话是否被重复添加 */
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->ptcpcomm_obj->session_id == ptcpcomm_obj->session_id)
            {
                OUTPUT("[PARSER-ERROR]The session[ID:%d] has been registered!\n", ptcpcomm_obj->session_id);
                return PARSER_ERROR_SESSION_REGISTERED;
            }
        }
    }
    
    /* 申请解析器会话结构空间 */
    ST_PARSER_SESSION *ptmp = (ST_PARSER_SESSION *)calloc(1, sizeof(ST_PARSER_SESSION));
    if(ptmp == NULL)
    {
        OUTPUT("[PARSER-ERROR]Calloc[%d] ST_PARSER_SESSION structure failed!\n", sizeof(ST_PARSER_SESSION));
        return PARSER_ERROR_MALLOC;
    }
    
    /* 更新解析器会话信息 */
    pthread_mutex_init(&ptmp->tx_mutex, NULL);
    ptmp->ptcpcomm_obj            = ptcpcomm_obj;
    ptmp->state                   = PARSER_SESSION_STAT_STANDBY;
    ptmp->exit_state              = PARSER_SUCCESS;
    ptmp->max_msg_seq             = 0;
    ptmp->flag_is_CMD_ACTION_run  = false;
    memcpy(ptmp->local_device_id, parser_obj->local_device_id, 28);
    
    /* 为解析器会话创建工作线程 */
    ptmp->flag_run = true;
    switch(parser_obj->protocol_version)
    {
        case PARSER_PROTOCOL_1:
        {
            if(pthread_create(&ptmp->tid, NULL, parser_version1_process, (void *)ptmp) != 0)
            {
                OUTPUT("[PARSER-ERROR]Create parser process[Version ID:%d] thread failed!\n", parser_obj->protocol_version);
                free(ptmp);
                return PARSER_ERROR_THREAD;
            }
        }
        break;
        default:
            OUTPUT("[PARSER-ERROR]There is no matching protocol!\n");
            free(ptmp);
            return PARSER_ERROR_PROTOCOL;
        break;
    }
    
    /* 初始化KAP时间 */
    gettimeofday(&ptmp->last_kap_time, NULL);
    
    /* 将解析器会话示例增加到解析器会话列表 */
    // ----------------------------------------
    // [说明]前面已经判断列表是否已满，此处无需
    //       再次判断。
    // ----------------------------------------
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] == NULL)
        {
            parser_obj->session_list[i] = ptmp;
            parser_obj->session_num++;
            OUTPUT("[PARSER-INFO]Add session[%d] to parser session list[%d]!\n", ptcpcomm_obj->session_id, i);
            break;
        }
    }
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：delete_session
//|  功能描述：从解析器删除一个待处理会话
//|  参数说明：指向解析器对象结构的指针，指向TCP_COMM通信对象的指针
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：对会话的标识通过会话ID完成
//|        若会话删除成功，指向解析器会话实例的原指针将被清空为NULL
//+------------------------------------------------------------------------------------------+
static int delete_session(struct parser * const parser_obj, ST_TCP_COMM **pptcpcomm_obj)
{
    int i;
    int ret;
    uint32_t session_id;
    
    /* 对象结构指针状态检查 */
    if(parser_obj == NULL || pptcpcomm_obj == NULL || *pptcpcomm_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[delete_session]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查解析器会话持有量 */
    if(parser_obj->session_num == 0)
    {
        OUTPUT("[PARSER-ERROR]Session list is empty!\n");
        return PARSER_ERROR_SESSION_LIST_EMPTY;
    }
    
    session_id = (*pptcpcomm_obj)->session_id;
    
    /* 在解析器会话列表中查找指定会话 */
    for(i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->ptcpcomm_obj->session_id == session_id)
            {
                OUTPUT("[PARSER-DEBUG]Find session[%d] in list[%d]!\n", session_id, i);
                
                if(parser_obj->session_list[i]->state == PARSER_SESSION_STAT_INIT)
                {
                    OUTPUT("[PARSER-WARNING]The session state[%d] does not support this operation!\n", parser_obj->session_list[i]->state);
                    return PARSER_ERROR_UNEXPECT_STATE;
                }
                
                break;
            }
        }
    }
    if(i >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Can't find session[%d] in parser session list!\n", session_id);
        return PARSER_ERROR_SESSION_NON_EXISTENT;
    }
    
    /* 切换会话运行状态 */
    pthread_mutex_lock(&parser_obj->session_list[i]->tx_mutex);
    parser_obj->session_list[i]->state = PARSER_SESSION_STAT_END;
    pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
    
    /* 关闭指令解析线程运行许可 */
    // ----------------------------------------
    // [说明]运行许可关闭后，线程可能仍会阻塞在
    //       等会话接收缓冲区非空的状态，因此接
    //       下来需要将TCP-COMM会话关闭。
    // ----------------------------------------
    parser_obj->session_list[i]->flag_run= false;
    parser_obj->session_list[i]->ptcpcomm_obj->stop(parser_obj->session_list[i]->ptcpcomm_obj);
    pthread_join(parser_obj->session_list[i]->tid, NULL);
    
    /* 停止指定的通信会话 */
    ret = tcp_comm_destroy(&parser_obj->session_list[i]->ptcpcomm_obj);
    if(ret < 0)
    {
        OUTPUT("[PARSER-WARNING]Destory TCP-COMM session failed with %#x!\n", ret);
    }
    
    /* 释放该会话占用的资源 & 从解析器会话列表中删除对该会话的记录 */
    pthread_mutex_destroy(&parser_obj->session_list[i]->tx_mutex);
    ST_PARSER_SESSION *ptmp = parser_obj->session_list[i];
    parser_obj->session_list[i] = NULL;
    parser_obj->session_num--;
    free(ptmp);
    
    *pptcpcomm_obj = NULL;
    
    OUTPUT("[PARSER-INFO]Delete session[%d] from parser session list[%d]!\n", session_id, i);
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：pack_data
//|  功能描述：向指定的会话发送数据，数据将被封装成Loice格式
//|  参数说明：指向解析器实例的指针，会话ID，消息序列号，消息数据，数据长度
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：当前实现中未对数据消息回应做处理，因此数据打包方法也默认使用无回应消息类型。
//|        该函数当前按照Loice Version1格式实现，未考虑指令版本扩展！
//+------------------------------------------------------------------------------------------+
static int pack_data(struct parser * const parser_obj, ST_INTERNAL_DATA *pinternal_data)
{
    int i = 0;
    int ret = -1;
    
    /* 参数检查 */
    if(pinternal_data == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[pack_data]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查解析器会话持有量 */
    if(parser_obj->session_num == 0)
    {
        OUTPUT("[PARSER-ERROR]Session list is empty!\n");
        return PARSER_ERROR_SESSION_LIST_EMPTY;
    }
    
    /* 在解析器会话列表中查找指定会话 */
    for(i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->ptcpcomm_obj->session_id == pinternal_data->session_id)
            {
                break;
            }
        }
    }
    if(i >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Can't find session[%d] in parser session list!\n", pinternal_data->session_id);
        return PARSER_ERROR_SESSION_NON_EXISTENT;
    }
    
    /* 获取会话发送锁 */
    pthread_mutex_lock(&parser_obj->session_list[i]->tx_mutex);
    /* 判断会话状态 */
    if(parser_obj->session_list[i]->state == PARSER_SESSION_STAT_INIT ||
       parser_obj->session_list[i]->state == PARSER_SESSION_STAT_EXIT ||
       parser_obj->session_list[i]->state == PARSER_SESSION_STAT_END)
    {
        OUTPUT("[PARSER-WARNING]The session state[%d] does not support this operation!\n", parser_obj->session_list[i]->state);
        pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 判断缓冲区剩余空间 */
    uint32_t tx_buf_unused_space = 0;
    uint32_t need_to_send_len = pinternal_data->data_length + MIN_PAYLOAD_DATA_LENGTH + sizeof(ST_LOICE_PROTO_VER_1_HEAD);
    ret = parser_obj->session_list[i]->ptcpcomm_obj->tx_buf.get_unused_space(&parser_obj->session_list[i]->ptcpcomm_obj->tx_buf, &tx_buf_unused_space);
    if(ret < 0)
    {
        OUTPUT("[PARSER-WARNING]Get Session[%d] TX_BUF unused space failed!\n", parser_obj->session_list[i]->ptcpcomm_obj->session_id);
        pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
        return PARSER_ERROR_OPERATION_FAIL;
    }
    if(tx_buf_unused_space < need_to_send_len)
    {
        OUTPUT("[PARSER-WARNING]Get Session[%d] TX_BUF space is not enough[%d < %d]!\n", parser_obj->session_list[i]->ptcpcomm_obj->session_id, tx_buf_unused_space, need_to_send_len);
        pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
        return PARSER_ERROR_UNEXPECT_DATA_LENGTH;
    }
    
    /* 构建并发送数据首部 */
    ST_LOICE_PROTO_VER_1_HEAD msg_head;
    loice_proto_version1_msg_head_build(parser_obj->session_list[i], &msg_head, pinternal_data, DATA_TYPE_NOREPLY);
    ret = parser_obj->session_list[i]->ptcpcomm_obj->send_data(parser_obj->session_list[i]->ptcpcomm_obj, (uint8_t *)&msg_head, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
    if(ret < 0)
    {
        OUTPUT("[PARSER-WARNING]Session[%d] send data 1 failed!\n", parser_obj->session_list[i]->ptcpcomm_obj->session_id);
        pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
        return PARSER_ERROR_OPERATION_FAIL;
    }
    
    /* 构建并发送数据体（固定部分） */
    ST_LOICE_PROTO_VER_1_BODY_MSG msg_body = {0};
    msg_body.data_type       = pinternal_data->data_type;
    msg_body.data_type_value = pinternal_data->data_type_value;
    msg_body.data_seq        = pinternal_data->data_seq;
    msg_body.pdata           = pinternal_data->pdata;
    msg_body.msg_body_check  = loice_proto_version1_data_body_checksum_calcu(&msg_body, pinternal_data->data_length);
    ret = parser_obj->session_list[i]->ptcpcomm_obj->send_data(parser_obj->session_list[i]->ptcpcomm_obj, (uint8_t *)&msg_body, MIN_PAYLOAD_DATA_LENGTH);
    if(ret < 0)
    {
        OUTPUT("[PARSER-WARNING]Session[%d] send data 2 failed!\n", parser_obj->session_list[i]->ptcpcomm_obj->session_id);
        pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
        return PARSER_ERROR_OPERATION_FAIL;
    }
    
    /* 发送数据体（可变部分） */
    if(pinternal_data->pdata != NULL)
    {
        ret = parser_obj->session_list[i]->ptcpcomm_obj->send_data(parser_obj->session_list[i]->ptcpcomm_obj, pinternal_data->pdata, pinternal_data->data_length);
        if(ret < 0)
        {
            OUTPUT("[PARSER-WARNING]Session[%d] send data 3 failed!\n", parser_obj->session_list[i]->ptcpcomm_obj->session_id);
            pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
            return PARSER_ERROR_OPERATION_FAIL;
        }
    }
    
    pthread_mutex_unlock(&parser_obj->session_list[i]->tx_mutex);
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：clear_cmd_action_flag
//|  功能描述：清空CMD_ACTION类指令的运行标志，会话ID
//|  参数说明：指向解析器对象结构的指针
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：
//+------------------------------------------------------------------------------------------+
static int clear_cmd_action_flag(struct parser * const parser_obj, uint32_t session_id)
{
    int i = 0;
    
    /* 对象结构指针状态检查 */
    if(parser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[clear_cmd_action_flag]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查解析器会话持有量 */
    if(parser_obj->session_num == 0)
    {
        OUTPUT("[PARSER-ERROR]Session list is empty!\n");
        return PARSER_ERROR_SESSION_LIST_EMPTY;
    }
    
    /* 在解析器会话列表中查找指定会话 */
    for(i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->ptcpcomm_obj->session_id == session_id)
            {
                /* 清除标志位 */
                parser_obj->session_list[i]->flag_is_CMD_ACTION_run = false;
                break;
            }
        }
    }
    if(i >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Can't find session[%d] in parser session list!\n", session_id);
        return PARSER_ERROR_SESSION_NON_EXISTENT;
    }
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_create
//|  功能描述：初始化解析器对象结构
//|  参数说明：用于输出解析器对象结构的指针、使用的通信协议版本和本地设备ID
//|  返回值说明：成功返回PARSER_SUCCESS，pparser_obj指针输出指向对象结构体的空间；
//|              失败返回错误码（负值）
//|  备注：若本地设备ID指针为NULL，则本地设备ID将被设置为保留的全0字段。
//|        若创建解析器失败，不会修改原指针的值。
//|        本地设备号数组长度必须不小于28字节。
//+------------------------------------------------------------------------------------------+
int parser_create(ST_PARSER **ppparser_obj, ENUM_PARSER_PROCOTOL_VERSION version, const uint8_t *plocal_device_id)
{
    /* 参数检查 */
    if(version == PARSER_PROTOCOL_INIT)
    {
        OUTPUT("[PARSER-ERROR]The version[%d] must be a positive integer!\n", version);
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    
    /* 对象结构指针状态检查 */
    if(ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 2 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(*ppparser_obj != NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 1 pointer must be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    
    /* 申请解析器结构空间 */
    ST_PARSER *ptmp = (ST_PARSER *)calloc(1, sizeof(ST_PARSER));
    if(ptmp == NULL)
    {
        OUTPUT("[PARSER-ERROR]Calloc[%d] ST_PARSER structure failed!\n", sizeof(ST_PARSER));
        return PARSER_ERROR_MALLOC;
    }
    
    /* 创建解析器管理线程 */
    ptmp->flag_manager_run = true;
    if(pthread_create(&ptmp->manager_tid, NULL, parser_manager_process, (void *)ptmp) != 0)
    {
        OUTPUT("[PARSER-ERROR]Create parser manager process thread failed!\n");
        free(ptmp);
        return PARSER_ERROR_THREAD;
    }
    
    /* 设置解析器配置参数 & 更新解析器对象结构 */
    ptmp->state            = PARSER_STAT_OK;
    ptmp->protocol_version = version;
    
    // ----------------------------------------
    // [说明]当plocal_device_id为NULL时，本地设
    //       备号为全0，calloc调用为其做了初始化。
    // ----------------------------------------
    if(plocal_device_id != NULL)
    {
        memcpy(ptmp->local_device_id, plocal_device_id, 28);
    }
    
    ptmp->add_session           = add_session;
    ptmp->delete_session        = delete_session;
    ptmp->pack_data             = pack_data;
    ptmp->clear_cmd_action_flag = clear_cmd_action_flag;
    
    *ppparser_obj = ptmp;
    
    OUTPUT("[PARSER-INFO]Parser[Version ID:%d] created.\n", ptmp->protocol_version);
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_destroy
//|  功能描述：去初始化解析器对象结构，释放其占用的空间并关闭其持有的会话
//|  参数说明：指向解析器对象结构指针的指针
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：若销毁解析器成功，原指针的值会被置为NULL。
//+------------------------------------------------------------------------------------------+
int parser_destroy(ST_PARSER **ppparser_obj)
{
    /* 对象结构指针状态检查 */
    if(ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 2 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(*ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 1 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if((*ppparser_obj)->state != PARSER_STAT_OK && (*ppparser_obj)->state != PARSER_STAT_TEMP)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support this operation[parser_destroy]!\n", (*ppparser_obj)->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 修改解析器实例状态以锁死解析器 */
    (*ppparser_obj)->state = PARSER_STAT_TEMP;
    
    /* 结束解析器管理线程 */
    (*ppparser_obj)->flag_manager_run = false;
    pthread_join((*ppparser_obj)->manager_tid, NULL);
    
    /* 遍历解析器会话列表，结束已有会话，回收会话资源 */
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if((*ppparser_obj)->session_list[i] != NULL)
        {
            delete_session(*ppparser_obj, &(*ppparser_obj)->session_list[i]->ptcpcomm_obj);
        }
    }
    
    /* 释放解析器本身所占资源 */
    free(*ppparser_obj);
    *ppparser_obj = NULL;
    
    return PARSER_SUCCESS;
}
